/*
 * @Author: lin_zizhuo 2297304135@qq.com
 * @Date: 2023-12-09 18:12:59
 * @LastEditors: lin_zizhuo 2297304135@qq.com
 * @LastEditTime: 2023-12-09 18:54:23
 * @FilePath: /thread_text/thread_mutex/mymutex.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <vector>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include "lockGuard.hpp"
using namespace std;
const int num = 4;
// 用多线程模拟抢票
int ticket = 5000;

struct threadDate
{
    string threadname;
    pthread_mutex_t *plock;
};

void *getTicket(void *args)
{
    threadDate *date = static_cast<threadDate *>(args);
    while (true)
    {
        // 在当前代码逻辑下，我们会发现有些线程抢到了<=0的号码的票
        // 这是一个非常严重的问题
        // 这个问题是由于ticket--操作不是一个原子性问题导致的，其在底层会被转化成三条汇编指令！！
        //  如何解决？ 加锁！
        // 这里必须保证所有的线程竞争的都是同一把锁
        // pthread_mutex_lock(date->plock);
        // 利用RAII, 做到锁的管理
        {
            // 这里的花括号是为了抢到票之后立刻将锁资源释放
            LockGuard lg(date->plock);
            if (ticket > 0)
            {
                usleep(10);
                printf("%s get ticket-%d\n", date->threadname.c_str(), ticket);
                ticket--;
            }
            else
            {
                // 这里直接break会导致死锁！！！
                //  pthread_mutex_unlock(date->plock);
                break;
            }
        }
        // pthread_mutex_unlock(date->plock);
        // 如果后面不做事情，可能会导致一个线程把票全抢完，因为这个线程拿到
        // 锁资源的竞争力更强
        usleep(15);
    }
    printf("%s quit...\n", date->threadname.c_str());
    return nullptr;
}

// 虽然栈空间需要独立，但是通过技术手段，是可以做到栈空间互相访问的！因为都存在于当前的地址空间中！

int main()
{
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);
    vector<pthread_t> threads;
    vector<threadDate *> tdd;
    // 创建多个线程
    for (int i = 0; i < num; ++i)
    {
        pthread_t tid = 0;
        threadDate *tddi = new threadDate;
        tddi->threadname = "thread-" + to_string(i);
        tddi->plock = &lock;
        tdd.push_back(tddi);
        pthread_create(&tid, nullptr, getTicket, tddi);
        threads.push_back(tid);
    }
    for (auto tid : threads)
        pthread_join(tid, nullptr);
    for (auto tddi : tdd)
        delete tddi;
    pthread_mutex_destroy(&lock);
    return 0;
}